﻿using System;
using System.Collections.Generic;
using System.Text;
using Mogre;
using MogreNewt;
using Miyagi.Common;
using Miyagi.Common.Resources;
using Miyagi.UI;
using Miyagi.UI.Controls;
using Miyagi.Common.Data;

namespace AplikacjaOgre
{
    /*
     * Tworzenie obiektu silniku gry przeprowadzającego komunikacje wszystkich obiektóww w grze.
     * Singleton - tylko jedyny obiekt. Brak możliwości dziedziczenia i ręcznego tworzenia instancji.
     */

    sealed class Game// : BetaGUIListener
    {
        static readonly Game instance;

        #region Definicja obiektów silnika Ogre

        public Root Root;

        public RenderWindow RenderWindow;

        public SceneManager SceneManager;

        public Camera Camera;

        public Viewport Viewport;

        #endregion

        #region Definicja obiektów wejscia - wyjscia

        public MOIS.Keyboard Keyboard;

        public MOIS.Mouse Mouse;

        public MOIS.InputManager InputManager;

        #endregion

        #region Definicja obiektów silnika fizykii

        public World NewtonWorld;

        public Debugger NewtonDebugger;

        #endregion

        #region Definicja obiektów gry

        public Terrain Terrain;

        public GameCamera GameCamera;

        public ObjectManager ObjectManager;

        int BodyId = 0;

        #endregion

        #region Tworzenie obiektu Engine

        //Konstruktor prywatny aby nie mc tworzyć obiektów
        private Game()
        {

        }

        static Game()
        {
            instance = new Game();
        }

        //Przy pierwszym wywołaniu odpalany jest statyczny kontruktor (powyzej)
        public static Game Instance
        {
            get
            {
                return instance;
            }
        }

        #endregion

        Mogre.MaterialPtr material;
        Overlay overlay;
        IList<Skin> skins;

        public MiyagiSystem sys;

        KinektController kinektController;

        GameState gameState = GameState.MENU;

        private void initialiseResources()
        {
            ConfigFile cf = new ConfigFile();
            cf.Load("Resources.cfg", "\t:=", true);

            var si = cf.GetSectionIterator();

            while (si.MoveNext())
            {
                foreach (var line in si.Current)
                {
                    ResourceGroupManager.Singleton.AddResourceLocation(line.Value, line.Key, si.CurrentKey);
                    System.Console.WriteLine(si.CurrentKey);
                }
            }

            ResourceGroupManager.Singleton.InitialiseAllResourceGroups();
        }

        private void makeWindow()
        {
            Root = new Root();

            if (!Root.RestoreConfig())
            {
                if (!Root.ShowConfigDialog())
                    return;
            }

            RenderWindow = Root.Initialise(true, "Testowa gierka do Kinnecta");
        }

        private void makeScene()
        {
            SceneManager = Root.CreateSceneManager(SceneType.ST_GENERIC);
            Camera = SceneManager.CreateCamera("Kamera główna");
            Viewport = RenderWindow.AddViewport(Camera);
            Camera.NearClipDistance = 0.1f;
            Camera.FarClipDistance = 1000;
        }

        private void makeMenu()
        {
            sys = new MiyagiSystem("Mogre");
            //skins = Skin.CreateFromXml("Media/Skins.xml");

            Miyagi.UI.Controls.Styles.BorderStyle b = new Miyagi.UI.Controls.Styles.BorderStyle();
            b.Thickness = new Thickness(20);
            b.UV = new RectangleF(10, 10, 100, 100);

            var font = TrueTypeFont.Create(sys, "DejaVuSans", "DejaVuSans.ttf", 12, 96, System.Drawing.FontStyle.Regular);

            var skin = new Skin("ButtonSkin");
            skin.SubSkins["ButtonSkin"] = new Miyagi.Common.Resources.Texture("texture.png");
            

            var gui = new GUI();

            var button1 = new Button
            {
                BorderStyle = b,
                Focused = true,
                Location = new Point(10, 10),
                Size = new Size(200, 50),
                Skin = skin,
                Text = "Hello World",
                TextStyle =
                {

                    Alignment = Alignment.MiddleCenter,
                    ForegroundColour = Colours.White,
                    Font = font,
                    
                }
            };

            gui.Controls.Add(button1);
            sys.GUIManager.GUIs.Add(gui);
           
        }

        private void makeInput()
        {
            MOIS.ParamList pl = new MOIS.ParamList();
            IntPtr window;

            RenderWindow.GetCustomAttribute("WINDOW", out window);
            pl.Insert("WINDOW", window.ToString());

            InputManager = MOIS.InputManager.CreateInputSystem(pl);
            Keyboard = (MOIS.Keyboard)InputManager.CreateInputObject(MOIS.Type.OISKeyboard, false);
            Mouse = (MOIS.Mouse)InputManager.CreateInputObject(MOIS.Type.OISMouse, false);
        }

        private void makeDepthView()
        {
            TextureManager.Singleton.CreateManual("DepthViewTexture", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D, 640, 480, 0, PixelFormat.PF_BYTE_BGRA, 14);
            material = MaterialManager.Singleton.Create("DepthViewTextureMaterial", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);

            material.GetTechnique(0).GetPass(0).CreateTextureUnitState("DepthViewTexture");
            material.GetTechnique(0).GetPass(0).SetSceneBlending(SceneBlendType.SBT_TRANSPARENT_ALPHA);

            overlay = OverlayManager.Singleton.Create("Test");

            // Create a panel.
            var panel = (PanelOverlayElement)OverlayManager.Singleton.CreateOverlayElement("Panel", "PanelElement");
            // Set panel properties.
            panel.MaterialName = "DepthViewTextureMaterial";
            panel.MetricsMode = GuiMetricsMode.GMM_PIXELS;
            panel.Width = 320;
            panel.Height = 240;
            panel.HorizontalAlignment = GuiHorizontalAlignment.GHA_LEFT;
            panel.VerticalAlignment = GuiVerticalAlignment.GVA_TOP;
            panel.Left = 0.5f;
            panel.Top = 0.5f;

            // Add the panel to the overlay.
            overlay.Add2D(panel);

            // Make the overlay visible.
            overlay.Show();
        }

        public void Inistialise()
        {

            makeWindow();
            initialiseResources();
            makeScene();
            makeMenu();
            makeInput();

  

            NewtonWorld = new World();
            NewtonDebugger = new Debugger(NewtonWorld);
            NewtonDebugger.Init(SceneManager);

            GameCamera = new GameCamera();
            ObjectManager = new ObjectManager();


            makeDepthView();

            kinektController = new KinektController();
        }

        public TexturePtr getTexture(String textureName)
        {
            return TextureManager.Singleton.GetByName(textureName);
        }

        unsafe public void Update()
        {
            if (1==2 && kinektController != null && kinektController.currentSceneMetaData != null)
            {
                TexturePtr texture = Game.Instance.getTexture("DepthViewTexture");
                HardwarePixelBufferSharedPtr pixelBuffer = texture.GetBuffer();

                pixelBuffer.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);

                PixelBox pixelBox = pixelBuffer.CurrentLock;
                IntPtr data = pixelBox.data;
                byte* dest = (byte*)data.ToPointer();

                //System.Console.WriteLine(kinektController.currentSceneMetaData.BytesPerPixel); //Daje rezultat 2 - czyli short z id użytkownika ktory tam jest

                byte* map = (byte*)kinektController.currentSceneMetaData.SceneMapPtr.ToPointer();

                for (int i = 0; i < kinektController.currentSceneMetaData.FullYRes; i++)
                {
                    dest = (byte*)data.ToPointer() + i * pixelBox.rowPitch * 4;

                    for (int j = 0; j < kinektController.currentSceneMetaData.FullXRes; j++)
                    {
                        int correct = j*2;
                        short cor = map[i * kinektController.currentSceneMetaData.FullXRes*2 + correct];

                        if (cor == kinektController.currentUserId)
                        {
                            dest[j*4] = 0x88;
                            dest[j*4 + 1] = 0x88;
                            dest[j*4 + 2] = 0x88;
                            dest[j*4 + 3] = 0x88;
                        }
                        else
                        {
                            dest[j*4] = 0xFF;
                            dest[j*4 + 1] = 0xFF;
                            dest[j*4 + 2] = 0xFF;
                            dest[j*4 + 3] = 0xFF;
                        }
                    }
                }

                pixelBuffer.Unlock();
            }

            switch (gameState)
            {
                case GameState.MENU:
                    
                    break;
            }

            if(sys!= null && !sys.IsDisposed)
                sys.Update();

            GameCamera.Update();
            ObjectManager.Update();

            NewtonWorld.Update(1f / 60f);
            Root.RenderOneFrame();

            Keyboard.Capture();
            Mouse.Capture();

            WindowEventUtilities.MessagePump();
        }

        public int getUniqueBodyId()
        {
            return BodyId++;
        }

        public void startManualControlling(Player player, int i, int j)
        {
            kinektController.BeginControlling(player);
            player.freeBodyParts(i, j);
        }

        public void Shutdown()
        {
            //sys.GUIManager.Dispose();
            
            kinektController.active = false;

            //sys.GUIManager.

            //while (kinektController.kamera.IsAlive) ;

            //GC.Collect();

            //Root.Dispose();
        }

        //public void onButtonPress(Button button)
        //{
        //    if (button == single)
        //    {
        //        Console.WriteLine("Play solo!");
        //    }
        //    else if (button == lanmulti)
        //    {
        //        Console.WriteLine("Play in LAN!");
        //    }
        //    else if (button == netmulti)
        //    {
        //        Console.WriteLine("Play in Internet!");
        //    }
        //    else
        //    {
        //        Console.WriteLine("*Some* button was pressed!");
        //    }
        //    //mGui.hide();
        //}
    }
}
